package function

import (
	"fmt"
	"reflect"
	"strings"

	"gitee.com/knowgo/ego/core/types"
	"gitee.com/knowgo/ego/core/validator"
	"gitee.com/knowgo/ego/log"
)

type Return struct {
	Type *types.TypeInfo
	Info *ResponseTypeInfo
	log  log.Logger
}

func ParseReturn(reponseTypes map[string]*ResponseTypeInfo, typ reflect.Type, location string, log log.Logger) (*Return, error) {
	var r = Return{log: log}
	_, err := r.parse(reponseTypes, typ, location, true)
	return &r, err
}

func (r *Return) IsArray() bool {
	return r.Type.IsSlice
}

// func (r *Return) Parse(typ reflect.Type, location string) error {
// 	var objSet = map[string]struct{}{}
// 	_, err := r.parse(objSet, typ, location, true)
// 	return err
// }

func (r *Return) parse(reponseTypes map[string]*ResponseTypeInfo, typ reflect.Type, location string, root bool) (*ResponseTypeInfo, error) {
	typeInfo, err := types.ParseType(typ, location)
	if err != nil {
		return nil, err
	}

	// 解析
	info := &ResponseTypeInfo{
		ID:      typeInfo.ID(),
		Type:    typeInfo.TypeName(),
		Time:    typeInfo.IsTime,
		Array:   typeInfo.IsSlice,
		KeyType: typeInfo.KeyTypeName(),
	}
	if root {
		r.Type, r.Info = typeInfo, info
	}

	if typeInfo.IsReferenceStruct && !typeInfo.IsTime {
		// 是自定义结构体
		_, ok := reponseTypes[typeInfo.ID()]
		if ok {
			// 已经解析过，不再解析
			info.TypeId = typeInfo.ID() // 指向结构体 ID
			return info, nil
		}
	}

	// objPool[info.ID] = info
	if typeInfo.IsReferenceStruct { // 指向类型是结构体
		// 添加到已经解析过的集合中
		if !typeInfo.IsTime {
			// 不是时间类型，添加到已解析字典
			reponseTypes[typeInfo.ID()] = info
		}

		count := typeInfo.ReferenceType.NumField()

		for n := 0; n < count; n++ {
			field := typeInfo.ReferenceType.Field(n)
			if !field.IsExported() {
				continue
			}
			loc := fmt.Sprintf("%s\n\t%s.%s", location, typeInfo.TypeName(), field.Name)
			res, err := r.parse(reponseTypes, field.Type, loc, false)
			if err != nil {
				return nil, err
			}
			// 解析 tag，并获取描述信息
			tag := validator.ParseTag(&field, func(tagItem string) {
				r.log.Warnf("tag %s is ignored%s", tagItem, loc)
			})
			if tag == nil {
				// 忽略此字段 json:"-"
				continue
			}
			res.Description = strings.Join(tag.Descriptions, ";")
			res.Name = tag.JsonName

			// res.Name = fdTag.FieldName // json:"name"
			info.Fields = append(info.Fields, res)
		}
	}
	return info, nil
}
